Thorium Server

Server-sent events

With Armeria's support, Thorium is able to serve server-sent events. A sample of how to serve server-sent events is available in the tutorial.

First, we should create a model of the event like so:

import com.linecorp.armeria.common.sse.ServerSentEvent

import java.time.{Duration, LocalDateTime}

case class TimestampSSE(dt: LocalDateTime, event: String) extends ServerSentEvent {
  override def retry(): Duration = null

  override val id: String = scala.util.Random.nextLong.toHexString

  override def comment(): String = null

  override def data(): String = dt.toString
}

For simplicity, the controller will have two methods, one for the client to listen for incoming messages, and the other to push messages.

Take note that in this example, whenever a client is connected, 5 ping messages will automatically be pushed. Additionally, one message is pushed whenever the route /sse/sendEvent is accessed.

import com.greenfossil.thorium.Request
import com.linecorp.armeria.common.ResponseHeaders
import com.linecorp.armeria.server.annotation.Get
import com.linecorp.armeria.server.streaming.ServerSentEvents
import model.TimestampSSE
import reactor.core.publisher.Sinks

import java.time.LocalDateTime
import java.util.concurrent.CompletableFuture

object SSEController {
  val sink = Sinks.many().multicast().directAllOrNothing[TimestampSSE]()
  val flux = sink.asFlux()

  @Get("/sse/subscribe")
  def subscribeToSSE = Action: request =>
    ServerSentEvents
      .fromPublisher(
        ResponseHeaders.of(200),
        flux.doOnSubscribe{_ =>
          // send 5 ping messages each time a client is connected
          CompletableFuture.runAsync(() =>
            (1 to 5).foreach{_ =>
              sink.tryEmitNext(TimestampSSE(LocalDateTime.now(), "ping"))
              Thread.sleep(1000)
            }
          )
        }
      )


  @Get("/sse/sendEvent")
  def sendEvent = Action: request =>
    val event = TimestampSSE(LocalDateTime.now(), "user-initiated")
    sink.tryEmitNext(event)
    s"Event Id: ${event.id}"
  

}
Test the endpoint using curl as such:
curl -v --http2 http://localhost:8080/sse/subscribe
Manually trigger an event by using the /sse/sendEvent endpoint:
curl -v http://localhost:8080/sse/sendEvent
For more information about server-sent events, visit MDN Web Docs.
Last modified on 22/11/2023, 3:53 pm